package com.xstudio.pvzreborn.block;

import com.xstudio.pvzreborn.PVZReborn;
import com.xstudio.pvzreborn.block.crop.AgeThreeCropBlock;
import com.xstudio.pvzreborn.block.machine.BlockPolarCraftingTable;
import com.xstudio.pvzreborn.block.machine.BlockSeedPacketCreator;
import com.xstudio.pvzreborn.block.tree.CherryTree;
import com.xstudio.pvzreborn.block.tree.NutTree;
import com.xstudio.pvzreborn.block.tree.StarFruitTree;
import com.xstudio.pvzreborn.event.custom.PVZRegistryEvent;
import com.xstudio.pvzreborn.utils.registry.BlockRegistrationHelper;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.minecraft.world.level.material.Material;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class BlockManager {

	public static final DeferredRegister<Block> BLOCK_REGISTER = DeferredRegister.create(ForgeRegistries.BLOCKS, PVZReborn.MOD_ID);
	private static final Map<String, RegistryObject<? extends Block>> BLOCKS = new HashMap<>();
	private static final Map<String, List<String>> BLOCK_STATE_MODEL = new HashMap<>();

	public static void init(IEventBus bus) {
		PVZReborn.LOGGER.info("Initializing blocks");
		BLOCK_REGISTER.register(bus);
		bus.addGenericListener(Block.class, BlockManager::onPVZBlockRegistering);
		registerMachine();
		registerCrop();
		registerCropBlock();
		registerTree();
		PVZReborn.LOGGER.info("Initialized blocks");
	}

	public static void onPVZBlockRegistering(PVZRegistryEvent.Post<Block> event) {
		String blockName = event.getName();
		String textureGroup = event.getTextureGroup();
		RegistryObject<? extends Block> object = event.getObject();
		BLOCKS.put(blockName, object);
		if (textureGroup != null) {
			BLOCK_STATE_MODEL.computeIfAbsent(textureGroup, (key) -> new ArrayList<>()).add(blockName);
		}
	}

	private static void registerMachine() {
		new BlockRegistrationHelper("machine")
				.addElement(BlockNames.SEED_PACKET_CREATOR, (blockName, properties) -> BlockSeedPacketCreator::new)
				.addElement(BlockNames.POLAR_CRAFTING_TABLE, (blockName, properties) -> BlockPolarCraftingTable::new)
				.register();
	}

	private static void registerCrop() {
		Properties cropProperties = Properties.of(Material.PLANT).noCollission().randomTicks().instabreak().sound(SoundType.CROP);
		new BlockRegistrationHelper("crop")
				.addElement(BlockNames.PEA_SEEDLINGS, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.properties(cropProperties)
				.removeBlockItemElement()
				.addElement(BlockNames.CLOVER, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.removeBlockItemElement()
				.properties(cropProperties)
				.addElement(BlockNames.CABBAGE, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.removeBlockItemElement()
				.properties(cropProperties)
				.addElement(BlockNames.GARLIC, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.removeBlockItemElement()
				.properties(cropProperties)
				.addElement(BlockNames.WHITE_TURNIP, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.properties(cropProperties)
				.addElement(BlockNames.CATTAIL, (blockName, properties) -> () -> new AgeThreeCropBlock(properties))
				.removeBlockItemElement()
				.properties(cropProperties)
				.register();
	}

	private static void registerTree() {
		Properties treeProperties = Properties.of(Material.PLANT).noCollission().randomTicks().instabreak().sound(SoundType.GRASS);
		new BlockRegistrationHelper("tree")
				.addElement(BlockNames.CHERRY_SAPLING, (blockName, properties) -> () -> new CherryTree(properties))
				.properties(treeProperties)
				.addElement(BlockNames.NUT_SAPLING, (blockName, properties) -> () -> new NutTree(properties))
				.properties(treeProperties)
				.addElement(BlockNames.STAR_FRUIT_SAPLING, (blockName, properties) -> () -> new StarFruitTree(properties))
				.properties(treeProperties)
				.register();
	}

	private static void registerCropBlock() {
		new BlockRegistrationHelper("crop_block")
				.addElement(BlockNames.SQUASH_BLOCK, (blockName, properties) -> () -> new Block(properties))
				.properties(Properties.of(Material.VEGETABLE))
				.register();
	}

	@NotNull
	public static Block getBlock(String name) {
		return Objects.requireNonNull(BLOCKS.get(name), "Unable to load block:" + name).get();
	}

	public static List<Block> getAllBlocks() {
		return BLOCK_REGISTER.getEntries().stream().map(RegistryObject::get).collect(Collectors.toList());
	}

	public static List<String> getBlockStateModel(String group) {
		return BLOCK_STATE_MODEL.get(group);
	}

}
